from flask import request, jsonify, current_app, make_response, json, session
from info import constants, db
from info import redis_store
from info.libs.yuntongxun.sms import CCP
from info.models import User
from info.utils.captcha.captcha import captcha
from info.utils.response_code import RET
from . import passport_blue
import re
import random
from datetime import datetime


# 用户退出登陆
# 请求路径：passport/logout
# 请求方式：pst
# 请求参数：无
# 返回值：errno, errmsg
@passport_blue.route('/logout', methods=["POST"])
def logout():
    """
    功能描述：退出登陆
    思路分析
        １．清除session
        ２．返回状态
    :return:
    """
    # １．清除session
    session.pop('user_id', None)
    session.pop('nick_name', None)
    session.pop('mobile', None)
    session.pop('is_admin', None)
    # ２．返回状态
    return jsonify(errno=RET.OK, errmsg='退出登陆成功')


# 用户登陆
# 请求路径：passport/login
# 请求方式：post
# 请求参数：mobile, password 手机号码，密码
# 返回值：errno, errmsg
@passport_blue.route('/login', methods=['POST'])
def login():
    """
    功能描述：登陆用户
    思路分析
        １．获取参数
        ２．校验参数，非空校验
        ３．通过手机号去数据库查找用户对象
        ４．判断用户是否存在
        ５．校验用户密码是否正确
        ６．保持用户登陆的状态session
        7.返回登陆状态
    :return:
    """

    # １．获取参数
    dict_data = request.json
    mobile = dict_data.get("mobile")
    password = dict_data.get("password")
    # ２．校验参数，非空校验
    if not all([mobile, password]):
        return jsonify(errno=RET.DATAERR, errmsg="参数不能为空")
    # ３．通过手机号去数据库查找用户对象
    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.REQERR, errmsg='查询用户异常')
    # ４．判断用户是否存在
    if not user:
        return jsonify(errno=RET.USERERR, errmsg='用户不存在')
    # ５．校验用户密码是否正确
    # if password != user.password_hash:
    if not user.check_passowrd(password):
        return jsonify(errno=RET.ROLEERR, errmsg='密码错误')
    # ６．保持用户登陆的状态session
    session['user_id'] = user.id
    session['nick_name'] = user.nick_name
    session['mobile'] = user.mobile

    # 6.1记录用户最后一个登陆时间
    user.last_login = datetime.now()
    # 设置自动提交
    # db.session.commit()
    # ７．返回状态
    return jsonify(errno=RET.OK, errmsg='登陆成功')


# 注册用户
# 请求路径：passport/register
# 请求方式：post
# 请求参数：mobile, sms_code, password 手机号，短信验证码，密码
# 返回值：errno, errmsg
@passport_blue.route('/register', methods=['POST'])
def register():
    """
    功能描述：注册功能
    思路分析：
        １．获取参数
        ２．校验参数，非空校验
        ３．校验手机号格式
        ４．根据手机号去寻找redis里的验证码
        ５．判断是否过期
        ６．删除redis中的短信验证码
        ７．判断是否和sms_code短信验证码相等
        ８．创建用户对象，设置属性
        ９．保存用户数据到mysql
        １０．返回注册状态
    :return:
    """
    # １．获取参数
    # json_data = request.data
    # dict_data = json.loads(json_data)

    dict_data = request.json  # 等同与上面两步
    mobile = dict_data.get('mobile')
    sms_code = dict_data.get('sms_code')
    password = dict_data.get('password')
    # ２．校验参数，非空校验
    if not all([mobile, sms_code, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误，不能为空')
    # ３．校验手机号格式
    if not re.match('1[135789]\d{9}', mobile):
        return jsonify(errno=RET.DATAERR, errmsg='手机号码格式错误')
    # ４．根据手机号去寻找redis里的验证码
    try:
        redis_sms_code = redis_store.get("sms_code:%s" % mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='获取验证码异常')
    # ５．判断是否过期
    if not redis_sms_code:
        return jsonify(errno=RET.DATAERR, errmsg='验证码已经过期')
    # ６．删除redis中的短信验证码
    try:
        redis_store.delete("sms_code:%s" % mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='删除验证码异常')
    # ７．判断是否和sms_code短信验证码相等
    if redis_sms_code != sms_code:
        return jsonify(errno=RET.DATAERR, errmsg='短信验证码填写有误')
    # ８．创建用户对象，设置属性
    user = User()
    user.nick_name = mobile
    user.mobile = mobile
    # user.password_hash = password
    # 使用加密方式储存密码
    user.password = password
    # ９．保存用户数据到mysql
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        #  发送失败回滚提交
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='注册用户失败')
    # １０．返回注册状态
    return jsonify(errno=RET.OK, errmsg='注册成功')


# 发送短信验证码
# 请求路径：passport/sms_code
# 请求方式：post
# 请求参数：mobile, image_code, image_code_id 手机号，图片验证码内容，图片验证码编号
# 返回值：errno, errmsg
@passport_blue.route('/sms_code', methods=['POST'])
def sms_code():
    """
    功能描述：短信验证码
    思路分析：
        １．获取参数
        ２．校验参数，非空校验
        ３．校验手机号格式是否正确
        ４．通过图片编号取出redis中验证码的内容
        ５．判断是否过期
        ６．删除redis中的图片验证码
        ７．判断是否和图片验证码内容相等
        ８．生成短信验证码
        ９．发送短信验证码，调用ccp方法
        １０．储存验证码到redis中
        １１．返回发送状态
　    """

    # １．获取参数
    json_data = request.data
    dict_data = json.loads(json_data)
    mobile = dict_data.get("mobile")
    image_code = dict_data.get("image_code")
    image_code_id = dict_data.get("image_code_id")
    # ２．校验参数，非空校验
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.NODATA, errmsg="参数不能为空")
    # ３．校验手机号格式是否正确
    if not re.match("1[35789]\d{9}", mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机格式错误')
    # ４．通过图片编号取出redis中验证码的内容
    try:
        redis_image_code = redis_store.get("image_code:%s" % image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='获取图片验证码异常')
    # ５．判断是否过期
    if not redis_image_code:
        return jsonify(errno=RET.NODATA, errmsg='图片验证码已过期')
    # ６．删除redis中的图片验证码
    try:
        redis_store.delete("image_code:%s" % image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='图片验证码操作异常')
    # ７．判断是否和图片验证码内容相等
    if image_code.lower() != redis_image_code.lower():
        return jsonify(errno=RET.USERERR, errmsg='验证码错误')
    # ８．生成短信验证码
    sms_code = '%06d' % random.randint(0, 999999)
    # ９．发送短信验证码，调用ccp方法
    # current_app.logger.debug('短信验证码：%s' % sms_code)
    ccp = CCP()
    try:
        resule = ccp.send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES / 60], 1)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.IPERR, errmsg="云通讯请求错误")

    if resule == -1:
        return jsonify(errno=RET.DATAERR, errmsg='短信发送失败')
    # １０．储存验证码到redis中
    try:
        redis_store.set("sms_code:%s" % mobile, sms_code, constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='保证图片验证码失败')
    # １１．返回发送状态
    return jsonify(errno=RET.OK, errmsg='发送成功')


# 获取返回一张图片
# 请求路径：passport
# 请求方式：GET
# 请求参数：随机字符串cur_id,pre_id cur_id:当前图片验证码编号，per_id上一个图片验证码编号
# 返回值：图片验证码
@passport_blue.route('/image_code')
def image_code():
    """
    功能描述：图片验证码
    思路分析：
        １．获取参数
        ２．校验参数，为空校验
        ３．生成图片验证码
        ４．将图片验证码保存到redis中
        ５．判断是否有上个验证码编号，有则删除
        ６．返回验证码
    :return:
    """
    # １．获取参数
    cur_id = request.args.get('cur_id')
    pre_id = request.args.get('pre_id')

    # ２．校验参数，为空校验
    if not cur_id:
        return jsonify(errno=RET.PARAMERR, errmsg='图片验证码编号不存在')
    # ３．生成图片验证码
    name, text, image_data = captcha.generate_captcha()
    # ４．将图片验证码保存到redis中
    try:
        redis_store.set('image_code:%s' % cur_id, text, constants.IMAGE_CODE_REDIS_EXPIRES)

        # ５．判断是否有上个验证码编号，有则删除
        if pre_id:
            redis_store.delete('image_code:%s' % pre_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR, errmsg='图片操作异常')
    # ６．返回验证码
    response = make_response(image_data)
    response.headers["Content-Type"] = 'image/jpg'
    return response
